第一次看到这个是在@勾股的微博上,当时想的是不是w3c又有什么草案了 ,css也可以有“作用域”的概念了。当仔细看了之后,原来并非如此。
简介
A CSS Module is a CSS file in which all class names and animation names are scoped locally by default
简而言之,它并不是一个官方的草案或者标准,而是在代码打包阶段的一个css前后处理器:可以将样式文件中的类名和选择器变得模块化(也就是只对该模块有效)。
它的核心概念就是:locan scope by default /局部作用域,我此时此刻联想到了”菊”部。。
更直接的说,其实它就是一个打包插件,在打包css代码的时候会帮你做些事情:
让使用者肆无忌惮的去写自己的css代码,不用担心会影响到其他样式。这个在多人合作的时候会大大减少你的烦恼和时间。
让css代码无忧无虑的跨模块使用
让css代码高度可复用
命名 通过Webpack或者Browserify,每个模块所用过的css 都会被单独编译打包,所以你可以在样式表中用通用的名字来命名。
举个例子,比如我们要制作一个按钮,它有两个状态:enabled和disabled。通常会这样命名和使用:
Before CSS Modules:button.css
1 2 3 .button { }.button--disabled { }.button--normal { }
1 <button class ="button button--enabled" > enabled</button >
这是传统的bem风格,但bem有个缺点:嵌套的让人懵逼了。。。
With CSS Modules : button.css
1 2 .disabled { }.normal { }
只需在样式中写最通用的命名。在所写的js模块中,引用css样式:
1 2 3 import styles from './button.css' ;buttonElem.outerHTML = `<button class=${styles.normal} >按钮</button>`
虽然它是通用命名,但经过编译后它真正的class一定是独一无二的。这就是css modules为你所做的。
1 2 3 <button class ="components_submit_button__normal__abc5436" > Processing... </button >
这里有个需要注意的地方:就是不要写base+overrides风格,用过空格隔开,比如这样:
1 `class=${[styles.normal, styles['in-progress']].join(" ")} `
css modules 推荐一个类应该有它所有的样式。
组合 如上面所说,css modules 不建议bem的风格,但我们如何复用或者共享一些样式呢?那就是接下来的:
CSS Modules’ most potent weapon, composition :
bem写法相应的变成这样:
1 2 3 4 5 6 7 8 9 10 11 .common { } .normal { composes : common; } .disabled { composes : common; }
看看 最后的输出结果:
1 2 3 4 <button class ="components_submit_button__common__abc5436 components_submit_button__normal__def6547" > 按钮 </button >
这样 你不需要 更改或者增加你的类名就可以复用和组合 各种基本样式,是不是很方便?
共享 使用compose来引用其他样式文件,不同于less的@import.
1 2 3 4 5 6 7 .primary { color : #720 ; } .secondary { color : #777 ; }
此时button.css需要引用color.css中的primary颜色:
1 2 3 4 5 .common { }.normal { composes : common; composes : primary from "./colors.css" ; }
这时候可以看到css modules 真的是把样式表每个样式基类独立出来了。
独立样式 有了compose 我们可以写很多基类,然后引用这些基类组成一个模块所需的样式
1 2 3 4 5 6 .element { composes : large from "./typography.css" ; composes : dark-text from "./colors.css" ; composes : padding-all-medium from "./layout.css" ; composes : subtle-shadow from "./effect.css" ; }
感觉就像写 js最小模块一样。 但你不需要关心逻辑,只需自己组合就好了。
React实践 webpack是目前前端构建打包工具的首选了,react的jsx 语法中的className配合css modules ,这样组合实在是太帅气了。
相信大家的webpack插件都有下面这个,这个也是实现css modules的插件.
1 extract-text-webpack-plugin :" ~0.9 .1 "
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 var webpack = require ('webpack' );var path = require ('path' );var ExtractTextPlugin = require ("extract-text-webpack-plugin" );module .exports = { module : { loaders: [ {test: /\.js?$/ , loaders: ['react-hot' , 'babel' ], exclude: /node_modules/ }, {test: /\.js$/ , exclude: /node_modules/ , loader: 'babel-loader' }, { test: /\.css$/ , loader: ExtractTextPlugin.extract('css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]' ), } ] }, entry: { 'bundle' :[ "webpack-dev-server/client?http://localhost:8080/" , "webpack/hot/dev-server" , path.resolve(__dirname, './src/index.js' )], }, output: { path: path.resolve(__dirname, 'dev' ), filename: "[name].js" , libraryTarget: "amd" }, resolve: { extensions:['' ,'.js' ,'.json' ] }, plugins: [ new webpack.HotModuleReplacementPlugin(), new ExtractTextPlugin('[name].css' ) ], proxy: { '/some/path*' : { target: 'https://other-server.example.com' , secure: false , }, } }
只需要修改css的loader就可以了。
下面就用button举例吧:
button.jsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 * Created by Aaronphy on 16/2/17. */ import React,{Component} from 'react' ;import { render } from 'react-dom' ;import styles from './style.css' ;export default class Button extends Component { constructor (){ super (); this .state ={ invalid:false } } handleClick(e){ this .setState({invalid:!this .state.invalid}); } render(){ const text = this .state.invalid ?'不可点击' :'可点击' ; const {invalid} = this .state; return ( <button className ={invalid?styles.invalid:styles.normal} onClick = {e => this.handleClick(e)}> {text} </button > ); } }
base.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 .common { width : 80px ; height :30px ; border :1px solid #ccc ; border-radius : 8px ; outline :none; } .primary { color :white; background-color : #37A3EC ; } .disabled { color : white; background-color : #cccccc ; }
style.css
1 2 3 4 5 6 7 .normal { composes : common primary from "./base.css" ; } .invalid { composes : common disabled from "./base.css" ; }
npm run start 下看看效果
参考 - CSS Modules